package com.daohang361.imqq.tool;

import java.util.ArrayList;
import com.daohang361.imqq.tea.Crypter;
/**
 * 用于解密接收到的byte内容，下面例子为解密0x91
 * <pre>
 *      byte[] allbyte=in.array();// IoBuffer in
 * 	    MyLoger.printByteToHex(in.getHexDump());
 *		in.position(in.limit());
 *		QQUser sessionQQ =(QQUser) ServiceContex.getSessionAttribute("myqq");
 *		if(sessionQQ!=null){
 *		MyByteReciveArray myArray = new MyByteReciveArray();
 *		myArray.init(allbyte);
 *		myArray.extractHead();//提取版本信息QQ号码等固定内容
 *		myArray.deleteTail();//去掉包尾
 * int command = myArray.getCommand();
 *		try {
 *			if (command == 0x91) {
 *				myArray.decryptRemain(QQ2011.QQ_LOGIN_FIX_91_key);//开始解密
 *				myArray.extract(0, 0);
 *				myArray.save();
 *				byte[] loginTime = myArray.extract(0, 3);//登陆时间
 *				sessionQQ.addAttr("loginTime", loginTime);
 *				myArray.save();
 *				byte[] ipByte = myArray.extract(0, 3);//登陆IP
 *			System.out.println("登陆IP：" + MyUtil.bytes2IP(ipByte));
 *				sessionQQ.addAttr("loginIp", ipByte);
 *				myArray.save();
 *				myArray.extract(0, 7);
 *				myArray.delete();
 *				byte[] token_91_length = myArray.extract(0, 1);//0091_Token长度：56字节
 *				sessionQQ.addAttr("token_91_length", token_91_length);
 *				myArray.save();
 *				byte[] Token91_data = myArray.extract(0, 55);
 *				System.out.println("Token91_data:"
 *						+ Hex2Bytes.bytesToHexString(Token91_data));
 *				myArray.save();
 *				sessionQQ.addAttr("Token91_data", Token91_data);
 *     catch(Exception e)
 *     System.out.println("command:0x"+Integer.toHexString(command)+"转换失败!继续本轮");
 *				e.printStackTrace();
 *		}
 *			sessionQQ.setLogintimes(sessionQQ.getLogintimes()+1);//登陆包前进
 *			sessionQQ.setPakage(sessionQQ.getPakage()+1);//登陆包自动增长
 *		return sessionQQ;
 *</pre>
 * @author <a href="http://www.daohang361.com">naner</a>
 *
 */

public class MyByteReciveArray {
	/**
	 * 用于保存解密后数组
	 */
	private ArrayList<byte[]> reciveData = new ArrayList<byte[]>(10);
	private byte[] pakage;
	private int command;
	private int qq;
	private int commandNote;
	
	/**
	 * 用于保存临时byte数组
	 */
	private byte[] tempByte =null;
	
	/**
	 * 用于保存剩余的数组
	 */
	private byte[] surplus=null;
	
	public void init(byte[] allbyte){
		surplus=allbyte;
	}
	
	/**
	 * 抽取头部信息,抽取固定统一QQ格式。
	 */
	public void extractHead()
	{
		int check = surplus[0];
		this.extract(0, 2);
		this.delete();//丢弃包头
		this.setCommand(MyUtil.bytes2Integer(extract(0, 1)));//保存命令
		this.delete();
		if(check==5)
		{
			System.out.println("图片05系列包");
			this.setCommandNote(MyUtil.bytes2Integer(extract(0, 1)));
		}
		this.setPakage(extract(0, 1));//保存包序号
		this.delete();
		byte[] tempQQ=extract(0, 3);
		this.setQq(MyUtil.bytes2Integer(tempQQ));//保存qq号码
		this.delete();
		this.extract(0, 2);
		this.delete();//丢弃后面后面连续3个0
	}
	
	/**
	 * 保存当前变量
	 */
	public void save() {
		if(tempByte!=null)
			{
			reciveData.add(tempByte);
			tempByte=null;
			}
		else
			System.out.println("there have no data to save");
	}
	/**
	 * 保存其它到数组
	 */
	public void save(byte[] src) {
		reciveData.add(src);
		
	}

	/**
	 * 此方法用于抛弃无用的解析结果,执行了delete后执行save或者decode后会报错
	 */
	public void delete() {
		tempByte=null;
	}
	/**
	 * 去掉尾巴最后一个byte "03"
	 */
	public void deleteTail(){
		byte[] temp = new byte[surplus.length-1];
		System.arraycopy(surplus, 0, temp, 0, surplus.length-1);
		surplus=temp;
	}
	
	/**
	 * 这个方法用于抽取某段byte内容,返回抽取内容，然后将临时内容串抽取的部分踢出，重新组合，
	 * 建议一般从零开始抽取，否则内部数组保存抽取序列将会与实际情况中序列顺序不一致。
	 * @param beginNow
	 * @param endNow
	 * @return byte[]
	 */
	public byte[] extract(int beginNow,int endNow){
		try {
			if (endNow < beginNow || beginNow < 0 || endNow < 0) {
				try {
					throw new Exception(
							"check the beginNow and endNow ,the endNow should not bigger than beginNow.");
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			byte[] temp1 = new byte[endNow - beginNow + 1];
			byte[] temp2 = new byte[surplus.length - temp1.length];
			System.arraycopy(surplus, beginNow, temp1, 0, temp1.length);
			System.arraycopy(surplus, 0, temp2, 0, beginNow);//将beginNow之前数据保存
			System.arraycopy(surplus, beginNow + temp1.length, temp2, beginNow,
					surplus.length - temp1.length - beginNow);
			tempByte = temp1;
			surplus = temp2;
			return temp1;
		} catch (Exception e) {
			//e.printStackTrace();
		}
		return null;
	}
	public int extractInt(int beginNow, int endNow) {
		try {
			if (endNow < beginNow || beginNow < 0 || endNow < 0) {
				try {
					throw new Exception(
							"check the beginNow and endNow ,the endNow should not bigger than beginNow.");
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			byte[] temp1 = new byte[endNow - beginNow + 1];
			byte[] temp2 = new byte[surplus.length - temp1.length];
			System.arraycopy(surplus, beginNow, temp1, 0, temp1.length);
			System.arraycopy(surplus, 0, temp2, 0, beginNow);//将beginNow之前数据保存
			System.arraycopy(surplus, beginNow + temp1.length, temp2, beginNow,
					surplus.length - temp1.length - beginNow);
			tempByte = temp1;
			surplus = temp2;
			return MyUtil.bytes2Integer(temp1);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return 0;
	}
	/**
	 * 抽取所有
	 * @return
	 */
	public byte[] extractAll(){
		tempByte=surplus;
		surplus=null;
		return tempByte;
	}
	/**
	 * 用于解密临时抽取段并返回结果
	 * @param  tea密钥
	 * @return 解密后byte数组
	 */
	public byte[] decryptThis(byte[] key){
		byte[] decrypt =  new Crypter().decrypt(tempByte, key);
		tempByte=decrypt;
		return decrypt;
	}
	
	/**
	 * 用于解密剩余所有部分
	 * @param  tea密钥
	 * @return 解密后byte数组
	 */
	public byte[] decryptRemain(byte[] key){
//		System.out.println("surplus:"+Hex2Bytes.bytesToHexString(surplus));
		System.out.println("key:"+Hex2Bytes.bytesToHexString(key));
		byte[] decrypt =  new Crypter().decrypt(surplus, key);
		if(decrypt!=null)//修改解密失败后，原始剩余字节就成为空的bug
			surplus=decrypt;
		return decrypt;
	}
	
	
	public void setPakage(byte[] pakage) {
		this.pakage = pakage;
	}

	public int getQq() {
		return qq;
	}
	
	public void setQq(int qq) {
		this.qq = qq;
	}

	public byte[] getPakage() {
		return pakage;
	}

	public int getCommand() {
		return command;
	}

	public void setCommand(int command) {
		this.command = command;
	}
	public boolean hasNext()
	{
		if(surplus!=null&&surplus.length>0)
			return true;
		else
			return false;
	}

	public int size() {
		if(surplus!=null&&surplus.length>0)
			return surplus.length;
		return 0;
	}

	public int getCommandNote() {
		return commandNote;
	}

	public void setCommandNote(int commandNote) {
		this.commandNote = commandNote;
	}

}
